Scroll to navigation

SHMOP(2) Руководство программиста Linux SHMOP(2)

ИМЯ

shmat, shmdt - операции с общей памятью

ОБЗОР

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);

ОПИСАНИЕ

Вызов shmat() подключает сегмент общей памяти с идентификатором shmid к адресному пространству вызывающего процесса. Адрес подключения, указанный в shmaddr, учитывается следующим образом:

Если значение shmaddr равно NULL, то система выбирает подходящий (неиспользуемый) адрес для подключения сегмента.

Если значение shmaddr не равно NULL, а в shmflg указан флаг SHM_RND, то подключение производится по адресу shmaddr, округлённому до ближайшего значения кратного SHMLBA. В противном случае shmaddr должно быть выровнено по адресу страницы, к которому производится подключение.

Если в shmflg указан флаг SHM_RDONLY, то сегмент подключается для чтения, и вызывающий процесс должен иметь право на чтение этого сегмента. Иначе подключаемый сегмент будет доступен для чтения и записи, и для этого у процесса должны быть соответствующие права. Сегментов, доступных только на запись, быть не может.

В shmflg может быть указан флаг SHM_REMAP (только в Linux) для обозначения того, что отображение сегмента должно замещать любые существующие отображения в диапазоне, начиная с shmaddr и до размера сегмента (обычно выдается ошибка EINVAL, если в этом диапазоне адресов уже есть отображение). В этом случае значение shmaddr не должно быть равно NULL.

Значение brk(2) вызывающего процесса от подключения не изменяется. При завершении работы процесса сегмент будет автоматически отсоединён. Один и тот же сегмент может быть подключён в адресное пространство процесса несколько раз, как только для чтения, так и для чтения-записи.

При успешном выполнении системный вызов shmat() обновляет поля структуры shmid_ds (см. shmctl(2)), связанной с общим сегментом памяти, следующим образом:

Полю shm_atime присваивается значение текущего времени.
Значение shm_lpid устанавливается равным идентификатору вызывающего процесса.
Значение shm_nattch увеличивается на 1.

Вызов shmdt() отключает сегмент общей памяти, находящийся по адресу shmaddr, от адресного пространства вызывающего процесса. Отключаемый сегмент должен быть подключён по адресу shmaddr с помощью вызова shmat().

При успешном выполнении вызов shmdt() обновляет поля структуры shmid_ds, связанной с общим сегментом памяти, следующим образом:

Полю shm_dtime присваивается значение текущего времени.
Значение shm_lpid устанавливается равным идентификатору вызывающего процесса.
Значение shm_nattch уменьшается на 1. Если оно становится равным 0 и сегмент помечен для удаления, то сегмент удаляется.

При вызове fork(2) потомки наследуют подключённые общие сегменты памяти.

При вызове execve(2) все подключённые общие сегменты памяти отключаются.

При вызове _exit(2) все подключённые общие сегменты памяти отключаются.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении shmat() возвращается адрес подключённого общего сегмента памяти; при ошибке возвращается (void *) -1, а в errno содержится код ошибки.

При успешном выполнении shmdt() возвращается 0; при ошибке возвращается -1, а в errno содержится код ошибки.

ОШИБКИ

Значения errno, устанавливаемые при возникновении ошибок в shmat():

Вызывающий процесс не имеет прав для подключения заданного типа и не имеет мандата CAP_IPC_OWNER.
Неправильное значение shmid, не выровненное (по границе страницы и не указан SHM_RND) или неправильное значение shmaddr, или невозможно подключить сегмент по адресу shmaddr, или был указан SHM_REMAP, но shmaddr равно NULL.
Невозможно выделить память для дескриптора или страничных таблиц.

Значения errno, устанавливаемые при возникновении ошибок в shmdt():

По адресу shmaddr подключённый общий сегмент памяти отсутствует; или значение shmaddr не выровнено по границе страницы.

СООТВЕТСТВИЕ СТАНДАРТАМ

SVr4, POSIX.1-2001.

В SVID 3 (или, возможно, более ранних версиях) тип аргумента shmaddr был изменён с char * на const void *, а тип результата shmat() — с char * на void * (в Linux libc4 и libc5 прототипы определены с char *; в glibc2 — void *).

ЗАМЕЧАНИЯ

Для улучшения переносимости программ при подключении общего сегмента памяти рекомендуется использовать shmat() с аргументом shmaddr, установленным в NULL. Необходимо учитывать, что сегмент памяти, подключаемый таким способом, в разных процессах может подключаться по разным адресам. Поэтому все указатели в области общей памяти должны быть не абсолютными, а относительными (как правило относительно адреса начала сегмента).

В Linux сегмент общей памяти можно подключить даже если он помечен для удаление. Однако в POSIX.1-2001 об этом ничего не сказано и многие другие реализации это не поддерживают.

На работу shmat() влияют следующие системные параметры:

Коэффициент округления нижней границы адреса сегмента. Должен быть выровнен со страницей. В настоящее время значение SHMLBA равно PAGE_SIZE.

Реализацией не ограничивается максимальное количество общих сегментов памяти на процесс (SHMSEG).

СМОТРИТЕ ТАКЖЕ

brk(2), mmap(2), shmctl(2), shmget(2), capabilities(7), shm_overview(7), svipc(7)

2008-06-03 Linux